package com.sunlands.zlcx.usercenter.service.status.common;

import com.google.common.collect.Lists;
import com.sunlands.zlcx.usercenter.client.LiveVideoService;
import com.sunlands.zlcx.usercenter.client.MessageService;
import com.sunlands.zlcx.usercenter.client.UserFriendsService;
import com.sunlands.zlcx.usercenter.common.cache.RedisDistributedLockImpl;
import com.sunlands.zlcx.usercenter.constant.LearningStatus;
import com.sunlands.zlcx.usercenter.constant.RedisKeyConst;
import com.sunlands.zlcx.usercenter.constant.YN;
import com.sunlands.zlcx.usercenter.domain.*;
import com.sunlands.zlcx.usercenter.exception.*;
import com.sunlands.zlcx.usercenter.repository.*;
import com.sunlands.zlcx.usercenter.service.*;
import com.sunlands.zlcx.usercenter.util.AsyncTaskManager;
import com.sunlands.zlcx.usercenter.util.BeanPropertiesUtil;
import com.sunlands.zlcx.usercenter.util.CalendarUtil;
import com.sunlands.zlcx.usercenter.util.StringUtil;
import com.sunlands.zlcx.usercenter.vo.UsersStudyInfoVO;
import com.sunlands.zlcx.usercenter.vo.UsersVO;
import com.sunlands.zlcx.usercenter.vo.feign.MessageVO;
import com.sunlands.zlcx.usercenter.vo.feign.UserFriendInfo;
import com.sunlands.zlcx.usercenter.vo.response.BusinessResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author gaoyanfeng
 * @create 2019-04-28 10:00
 **/
@Slf4j
public abstract class AbstractStudyStatus implements ITypeStatus, BeanPropertiesUtil {

    @Autowired
    AsyncTaskManager asyncTaskManager;
    @Resource(name = "vipTaskExecutor")
    AsyncTaskExecutor vipTaskExecutor;

    protected void sendMessage(Long userId, String content) {
        asyncTaskManager.getExecutor().submit(() -> {
            try {
                MessageVO messageVO = new MessageVO();
                messageVO.setBusinessId(userId + "");

                BusinessResult<List<UserFriendInfo>> friendsResult = tzUserFriendsService.findFriendsPage(userId);
                BusinessResult.checkBusinessResult(friendsResult);
                List<UserFriendInfo> friendInfoList = friendsResult.getData();
                if (null != friendInfoList && friendInfoList.size() > 0) {
                    List<Long> friendIdList = Lists.newArrayList();
                    friendInfoList.forEach(r -> {
                        friendIdList.add(r.getFriendsUserId());
                    });
                    messageVO.setContent("TA" + content);
                    messageVO.setType("700");
                    messageVO.setUserIds(friendIdList);
                    BusinessResult.checkBusinessResult(messageService.sendMessage(messageVO));
                }
            } catch (Exception e) {
                log.error("", e);
                sendExceptionUtil.sendException("调用消息系统异常,用户id:" + userId, e);
            }
        });
    }

    protected void saveStudyInfo(UsersStudyInfoVO studyInfo, UsersTargetRelationDO targetRelation) {
        asyncTaskManager.getExecutor().submit(() -> {
            try {
                UsersStudyInfoDO usersStudyInfoDO = new UsersStudyInfoDO();
                copyNonNullProperties(studyInfo, usersStudyInfoDO);
                usersStudyInfoDO.setTargetId(targetRelation.getTargetId());
                if (null != studyInfo.getEndTime()) {
                    int studyMinutes = CalendarUtil.seconds2Minutes(studyInfo.getStudyMinuteSeconds()).intValue();
                    if (studyMinutes > 480) {
                        usersStudyInfoDO.setStudyMinutes(480);
                        studyInfo.setStudyMinuteSeconds(28800);
                    } else {
                        usersStudyInfoDO.setStudyMinutes(studyMinutes == 0 ? 1 : studyMinutes);
                    }
                    usersStudyInfoDO.setCountTime(CalendarUtil.getDateHoursBefore(studyInfo.getStartTime(), 3));
                } else {
                    usersStudyInfoDO.setCountTime(CalendarUtil.getCurrentHoursBefore(3));
                }
                usersStudyInfoDO.setWeek(CalendarUtil.getWeek(usersStudyInfoDO.getCountTime()));
                usersStudyInfoDO.setStatus(YN.YES.getCode());
                usersStudyInfoDO.setStudyInfoName(studyInfo.getStudyInfoName());
                usersStudyInfoDO.setRelateId(studyInfo.getRelateId());
                usersStudyInfoRepository.save(usersStudyInfoDO);
            } catch (Exception e) {
                log.error("保存学习生活记录异常 usersStudyInfoVO={}, usersTargetRelationDO={}, e={}", studyInfo, targetRelation, e);
                sendExceptionUtil.sendException("保存学习生活记录异常usersStudyInfoVO=[" + studyInfo + "]" + e, e);
            }
        });
    }

    protected void updateStudyHours(UsersTargetRelationDO targetRelation) {

        Long sumLearningTimeToday;
        try {
            sumLearningTimeToday = usersLearnTimingRepository.sumLearningTimeTarget(targetRelation.getUserId());
            log.info("usersTargetRelationDO ={}, sumLearningTimeToday={}", targetRelation, sumLearningTimeToday);
            if (null != sumLearningTimeToday) {
                targetRelation.setStudyHours(CalendarUtil.seconds2Minutes(sumLearningTimeToday.intValue()));
                usersTargetRepository.save(targetRelation);
            }
        } catch (Exception e) {
            log.error("", e);
            sendExceptionUtil.sendException("更新用户学习目标时长异常 userId= " + targetRelation.getUserId() + " e =" + e, e);
        }
    }

    protected void saveStudyInfoAndUpdateHours(UsersStudyInfoVO studyInfo, UsersTargetRelationDO targetRelation) {
        // 保存学习生活
        saveStudyInfo(studyInfo, targetRelation);

        // 更新目标学习时长hours
        updateStudyHours(targetRelation);
    }

    protected void learnTimingProcess(UsersStudyInfoVO studyInfo, UsersTargetRelationDO targetRelation, Long userId) {
        if (null == studyInfo.getEndTime()) {
            throw new CheckParamException("结束时间不能为空");
        }
        String studyNameKey = RedisKeyConst.getStudyName(userId);
        Object o = redisTemplate.opsForValue().get(studyNameKey);
        if (null == o) {
            log.warn("学习名称缓存为空 userId={}", userId);
            o = "学习";
        }
        log.debug("保存学习信息 usersStudyInfoVO = {} ", studyInfo);
        studyInfo.setStudyInfoName(Objects.nonNull(studyInfo.getStudyInfoName()) ? studyInfo.getStudyInfoName() : (String) o);
        if(StringUtils.isNotBlank(studyNameKey)){
            redisTemplate.delete(studyNameKey);
        }
        UsersLearnTimingDO usersLearnTimingDO = usersLearnTimingRepository.findByUserIdAndStatusOne(userId, YN.NO.getCode());
        LearnContentDO contentDO = null;
        if (Objects.nonNull(usersLearnTimingDO.getContentId())) {
            contentDO = usersLearnService.findOne(usersLearnTimingDO.getContentId());
            if (Objects.nonNull(contentDO)) {
                studyInfo.setStudyInfoName(contentDO.getContent());
                if (contentDO.getModel().intValue() == LearnContentDO.ModelEnum.valid.code.intValue() && contentDO.getMinutes() * 60 < studyInfo.getStudyMinuteSeconds()) {
                    studyInfo.setStudyMinuteSeconds(contentDO.getMinutes() * 60);
                }
            }
        }
        BigDecimal studyMinutes = CalendarUtil.seconds2Minutes(studyInfo.getStudyMinuteSeconds());
        if (studyMinutes.intValue() < 60) {
            if (studyMinutes.compareTo(BigDecimal.ONE) < 0) {
                sendMessage(userId, "结束了1分钟学习");
            } else {
                sendMessage(userId, "结束了" + studyMinutes + "分钟学习");
            }
        } else {

            studyMinutes = studyMinutes.intValue() > 480 ? BigDecimal.valueOf(480L) : studyMinutes;
            sendMessage(userId, "结束了" + CalendarUtil.seconds2Minutes(studyMinutes.intValue()) + "小时学习");
        }


        UsersVO usersVO = usersService.findOne(userId);
        // 新版本2.1
        usersLearnTimingDO.setStatus(YN.YES.getCode());
        usersLearnTimingDO.setStudyMinutes(studyMinutes.intValue() == 0 ? 1 : studyMinutes.intValue());
        usersLearnTimingDO.setEndTime(studyInfo.getEndTime());
        usersLearnTimingDO.setLearnName(studyInfo.getStudyInfoName());
        studyInfo.setStartTime(usersLearnTimingDO.getStartTime());
        saveLearningTime(studyInfo, targetRelation, usersLearnTimingDO);
        log.debug("usersLearnTimingDO ={}", studyInfo);
        if (usersLearnTimingDO.getType().intValue() == UsersStudyInfoDO.TypeEnums.LIAN_MAI.code.intValue()) {
            vipTaskExecutor.execute(() -> vipUserService.reduceTime(usersLearnTimingDO.getUserId(), (long) usersLearnTimingDO.getStudyMinutes()));
        }
        asyncTaskManager.getExecutor().submit(() -> {
            // 更新分享信息
            if (UsersStudyInfoDO.TypeEnums.create(studyInfo.getType()) == UsersStudyInfoDO.TypeEnums.ORDERNARY_COUNT_TIME) {
                shareService.updateShareContentAndStatusByLearnId(usersLearnTimingDO.getId(), 3, usersLearnTimingDO.getLearnName(), usersVO.getName());
            }
            // 新增或更新月统计信息
            String yearMonths = CalendarUtil.getDateString(usersLearnTimingDO.getCountTime(), CalendarUtil.SHORT_DATE_FORMAT_YYYY_MM);
            UserMonthLearnDO userMonthLearnDO = userMonthLearnRepository.findByUserIdAndYearMonths(userId.intValue(), yearMonths);

            if (Objects.isNull(userMonthLearnDO)) {
                userMonthLearnDO = UserMonthLearnDO
                        .builder()
                        .monthStudyMinutes(usersLearnTimingDO.getStudyMinutes())
                        .targetId(usersLearnTimingDO.getTargetId())
                        .yearMonths(yearMonths)
                        .countTime(usersLearnTimingDO.getCountTime())
                        .userId(userId.intValue())
                        .build();
                userMonthLearnRepository.save(userMonthLearnDO);
            } else {
                int monthTotalStudyMinutes = userMonthLearnDO.getMonthStudyMinutes() + usersLearnTimingDO.getStudyMinutes();
                userMonthLearnDO.setMonthStudyMinutes(monthTotalStudyMinutes);
                userMonthLearnRepository.save(userMonthLearnDO);
            }

            // 新增或更新日统计信息
            String yearMonthsDay = CalendarUtil.getDateString(usersLearnTimingDO.getCountTime(), CalendarUtil.SHORT_DATE_FORMAT);
            UserDayLearnDO byUserIdAndYearMonths = userDayLearnRepository.findByUserIdAndYearMonthsDay(userId, yearMonthsDay);
            int ordernaryTime = 0;
            int lianmaiTime = 0;
            if (UsersStudyInfoDO.TypeEnums.LIAN_MAI == UsersStudyInfoDO.TypeEnums.create(usersLearnTimingDO.getType())) {
                lianmaiTime = usersLearnTimingDO.getStudyMinutes();
            } else {
                ordernaryTime = usersLearnTimingDO.getStudyMinutes();
            }
            if (null == byUserIdAndYearMonths) {
                userDayLearnRepository.save(new UserDayLearnDO(userId, yearMonths, yearMonthsDay, ordernaryTime, lianmaiTime,
                        usersLearnTimingDO.getTargetId()));
            } else {
                byUserIdAndYearMonths.setLianmaiMinutes(byUserIdAndYearMonths.getLianmaiMinutes() + lianmaiTime);
                byUserIdAndYearMonths.setOrdernaryMinutes(byUserIdAndYearMonths.getOrdernaryMinutes() + ordernaryTime);
                byUserIdAndYearMonths.setStudyMinutes(byUserIdAndYearMonths.getOrdernaryMinutes() + byUserIdAndYearMonths.getLianmaiMinutes());
                userDayLearnRepository.save(byUserIdAndYearMonths);
            }


        });
        log.info("学习计时结束后，更新用户状态");
        usersService.updateStatus(userId, LearningStatus.NO_TIMING.getCode(), null, null, null);
        if (Objects.nonNull(usersLearnTimingDO.getContentId()) && usersLearnTimingDO.getContentId() > 0) {
            contentDO.setStatus(LearningStatus.NO_TIMING.getCode());
            usersLearnService.update(contentDO);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    public void saveLearningTime(UsersStudyInfoVO usersStudyInfoVO, UsersTargetRelationDO usersTargetRelationDO, UsersLearnTimingDO usersLearnTimingDO) {
        UsersLearnTimingDO save = usersLearnTimingRepository.save(usersLearnTimingDO);
        if (null != save.getStudyMinutes() && save.getStudyMinutes() > 0) {
            usersStudyInfoVO.setRelateId(save.getId());
            saveStudyInfoAndUpdateHours(usersStudyInfoVO, usersTargetRelationDO);
        }
    }


    protected void deleteUserTarget(UsersTargetRelationDO usersTargetRelationDO, Long userId) {
        // 同步用户表
        usersService.updateCurrentLearnTarget(userId, null, null);
        usersTargetRelationDO.setStatus(YN.NO.getCode());
        usersTargetRelationDO.setEndTime(new Date());
        usersTargetRepository.save(usersTargetRelationDO);
    }

    protected void checkTimingPeriod(UsersStudyInfoVO usersStudyInfoVO, Long userId) {
        if (StringUtil.isEmpty(usersStudyInfoVO.getStudyInfoName())) {
            throw new IllegalArgumentException("学习计时名称不能为空");
        }
        Date lastLearningEndTime = usersLearnTimingRepository.getLastLearningEndTime(userId);
        if (null != lastLearningEndTime) {
            if (null != usersStudyInfoVO.getStartTime() && usersStudyInfoVO.getStartTime().getTime() < lastLearningEndTime.getTime()) {
                throw new IllegalArgumentException("用户不能在该时段学习");
            }
            if (null == usersStudyInfoVO.getStartTime() && System.currentTimeMillis() < lastLearningEndTime.getTime()) {
                throw new IllegalArgumentException("用户不能在该时段学习");
            }
        }
        UsersVO usersVO = usersService.findOne(userId);
        checkStatus(usersStudyInfoVO.getType(), usersVO);
    }

    public static void checkStatus(Integer studyType, UsersVO usersVO) {
        if (LearningStatus.NO_TIMING != LearningStatus.getLearningStatus(usersVO.getStatus())) {
            LearningStatus status = LearningStatus.getLearningStatus(usersVO.getStatus());
            UsersStudyInfoDO.TypeEnums typeEnums = UsersStudyInfoDO.TypeEnums.create(studyType);
            if (LearningStatus.LEARN_TIMING == status) {
                throw new UserLiveLearningException("您正在专注计时，结束后才能开始" + typeEnums.getTitle() + "~");
            } else if (LearningStatus.LIAN_MAI_TIMING == status) {
                throw new UserLiveLearningException("您正在连麦计时，结束后才能开始" + typeEnums.getTitle() + "~");
            } else if (LearningStatus.TIME_LEARN_ROOM == status) {
                throw new UserTimeRoomLearningException("您正在自习室计时，结束后才能开始" + typeEnums.getTitle() + "~");
            } else {
                throw new UserTimeLearningException("用户之前的学习未结束，结束后才能开始~");
            }
        }
    }

    @Autowired
    protected UsersServiceImpl usersService;
    @Autowired
    protected UsersTargetRepository usersTargetRepository;
    @Autowired
    protected UsersStudyInfoRepository usersStudyInfoRepository;
    @Autowired
    @Lazy
    protected UsersStudyServiceImpl usersStudyService;
    @Autowired
    protected UsersLearnTimingRepository usersLearnTimingRepository;
    @Autowired
    protected MessageService messageService;
    @Autowired
    protected UserFriendsService tzUserFriendsService;
    @Autowired
    protected RedisTemplate redisTemplate;
    @Autowired
    protected SendExceptionUtil sendExceptionUtil;
    @Autowired
    protected LiveVideoService liveVideoService;
    @Autowired
    protected UsersShareServiceImpl shareService;
    @Autowired
    protected RedisDistributedLockImpl redisDistributedLock;
    @Autowired
    protected UserMonthLearnRepository userMonthLearnRepository;
    @Autowired
    protected UserDayLearnRepository userDayLearnRepository;
    @Autowired
    protected VipUserServiceImpl vipUserService;
    @Autowired
    protected UsersLearnContentServiceImpl usersLearnService;
}
